#encoding=utf8
'''
Created on May 11, 2015

@author: jingyang <jingyang@smalltreemedia.com>
'''
from django.contrib import admin
from django.shortcuts import get_object_or_404
from django.utils import timezone

from prd_order.models import ProductionOrder, OrderStatusRecord, Project,\
    Procedure
from prd_order.forms import ProductionOrderAdminForm, ProjectAdminForm,\
    ProcedureForm
from utils import field, plaintext2html, DateListFilter


class OrderStatusRecordInline(admin.TabularInline):
    model = OrderStatusRecord
    can_delete = False
    extra = 0
    suit_classes = 'suit-tab suit-tab-status_record'
    readonly_fields = ('status_before', 'status_after', 'editor', 'time')

    def get_formset(self, request, obj=None, **kwargs):
        if obj:
            self.max_num = obj.orderstatusrecord_set.count()
        return admin.TabularInline.get_formset(self, request, obj=obj, **kwargs)


class ReceivedYearListFilter(DateListFilter):
    title = 'Received at Year'
    parameter_name = 'year'
    filter_field = 'date_received'


class ReceivedMonthListFilter(DateListFilter):
    title = 'Received at Month'
    parameter_name = 'month'
    filter_field = 'date_received'


class ReceivedDayListFilter(DateListFilter):
    title = 'Received at Day'
    parameter_name = 'day'
    filter_field = 'date_received'


class ProductionOrderAdmin(admin.ModelAdmin):
    list_per_page = 20
    list_filter = ('status', 'to', ReceivedYearListFilter,
        ReceivedMonthListFilter, ReceivedDayListFilter,
        'studio_clouds', 'studio')
    search_fields = ('order_id', 'editor', 'ref_num', 'working_title')
    list_display = ('get_ref_num_title', 'get_editor', 'date_received',
        'to', 'studio_clouds', 'studio', 'get_app_store', 'get_status',
        'get_assign_team', 'get_assign_pjm', 'get_project')
    form = ProductionOrderAdminForm
    id_fields = ('Basic Info', {'classes': ('suit-tab', 'suit-tab-basic'), 'fields': ('order_id', 'editor', 'create_time')})
    info_fields = ('Order Info', {'classes': ('suit-tab', 'suit-tab-basic'), 'fields':
        (
        'ref_num',
        'date_issued',
        'date_received',
        'issued_by',
        'to',
        'studio_clouds',
        'studio',
        'working_title',
        'story_line',
        'mode',
        'app_store',
        'content',
        'reference',
        'remarks',
        )
    })
    readonly_info_fields = ('Brief Info', {'classes': ('suit-tab', 'suit-tab-basic'), 'fields':
        (
        'ref_num',
        'date_issued',
        'date_received',
        'get_issued_by',
        'to',
        'studio_clouds',
        'studio',
        'working_title',
        'story_line',
        'mode',
        'get_app_store',
        'get_content',
        'get_reference',
        'get_remarks',
        )
    })
    confirmation_fields = ('Confirmation Info', {'classes': ('suit-tab', 'suit-tab-basic'), 'fields':
        (
        'status',
        'assign_team',
        'assign_pjm',
        )
    })
    readonly_confirmation_fields = ('Confirmation Info', {'classes': ('suit-tab', 'suit-tab-basic'), 'fields':
        (
        'status',
        'get_assign_team',
        'get_assign_pjm',
        )
    })

    class Media:
        js = ('base/js/custom_production_order.js',)

    def get_fieldsets(self, request, obj=None):
        if obj:
            self.suit_form_tabs = (('basic', 'Production Brief'), ('status_record', 'Status Change Log'))
            if obj.status == 'C':
                self.confirmation_fields[1].update({'fields': ('status',
                    'assign_team', 'assign_pjm', 'confirmed_date',)})
                if not self.has_add_permission(request):
                    self.readonly_confirmation_fields[1].update({'fields': ('status',
                        'get_assign_team', 'get_assign_pjm', 'confirmed_date',)})
                    return (self.id_fields, self.readonly_info_fields,
                        self.readonly_confirmation_fields)
                return (self.id_fields, self.readonly_info_fields, self.confirmation_fields)
            else:
                self.confirmation_fields[1].update({'fields': ('status',
                    'assign_team', 'assign_pjm',)})
                if not self.has_add_permission(request):
                    self.readonly_confirmation_fields[1].update({'fields': ('status',
                        'get_assign_team', 'get_assign_pjm',)})
                    return (self.id_fields, self.readonly_info_fields, self.readonly_confirmation_fields)
                return (self.id_fields, self.info_fields, self.confirmation_fields)
        else:
            self.suit_form_tabs = (('basic', 'Production Brief'),)
            return (self.info_fields,)

    @field('Project ID', allow_tags=True, admin_order_field='project')
    def get_project(self, obj):
        return "<a href='/admin/prd_order/project/%s/' target='_blank'>%s</a> - %s" %\
            (obj.project.pk, obj.project, obj.project.get_status_display())

    @field('Production Brief', admin_order_field='ref_num')
    def get_ref_num_title(self, obj):
        return obj.get_ref_num_title()

    @field('Structural Guidelines/Content', allow_tags=True)
    def get_content(self, obj):
        return plaintext2html(obj.content)

    @field('Cultural/Visual References', allow_tags=True)
    def get_reference(self, obj):
        return plaintext2html(obj.reference)

    @field('Remarks', allow_tags=True)
    def get_remarks(self, obj):
        if not obj.remarks:
            return ''
        return plaintext2html(obj.remarks)

    @field('Assign to Production Team', admin_order_field='assign_team')
    def get_assign_team(self, obj):
        return obj.assign_team or ''

    @field('Assign to PJM', admin_order_field='assign_pjm')
    def get_assign_pjm(self, obj):
        return obj.assign_pjm or ''

    @field('Created By', admin_order_field='editor')
    def get_editor(self, obj):
        return obj.editor.split('@')[0]

    @field('Confirmation Status', allow_tags=True, admin_order_field='status')
    def get_status(self, obj):
        cls = 'label-info'
        if obj.status == 'P':
            cls = 'label-warning'
        elif obj.status == 'C':
            cls = 'label-success'
        elif obj.status == 'X':
            cls = ''
        elif obj.status == 'D':
            cls = 'label-important'
        return "<span class='label %s' style='width: 50px;'><center>%s</center></span>" % (cls, obj.get_status_display())

    @field('App Store', allow_tags=True, admin_order_field='app_store')
    def get_app_store(self, obj):
        stores = obj.get_app_store()
        if not stores:
            return ""
        for k, v in enumerate(stores):
            if v == 'iTunes App Store':
                img = 'app_store.png'
            elif v == 'Google Play':
                img = 'google_play.png'
            elif v == 'Amazon App Store':
                img = 'amz_store.png'
            stores[k] = "<img src='/static/base/img/%s' width=25 height=25 />" % img
        return "&nbsp;".join(stores)

    @field('Issued By')
    def get_issued_by(self, obj):
        return obj.get_issued_by()

    @field('Required Release Date')
    def get_required_release_date(self, obj):
        return obj.get_required_release_date()

    def get_inline_instances(self, request, obj=None):
        if obj:
            self.inlines = [OrderStatusRecordInline]
        else:
            self.inlines = []
        return admin.ModelAdmin.get_inline_instances(self, request, obj=obj)

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = admin.ModelAdmin.get_actions(self, request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    def get_readonly_fields(self, request, obj=None):
        base = ('order_id', 'editor', 'create_time', 'issued_by_text', 'confirmed_date')
        if obj:
            if obj.status == 'C' or not self.has_add_permission(request):
                base += self.info_fields[1]['fields']
                base += self.readonly_info_fields[1]['fields']
            if not self.has_add_permission(request):
                base += self.readonly_confirmation_fields[1]['fields']
            base = tuple(set(base))
        return base

    def save_model(self, request, obj, form, change):
        if not self.has_add_permission(request):
            return
        now = timezone.now()
        if not change:
            obj.order_id = 'PO-%s%02i%02i%02i' % (now.year, now.month, now.day,
                ProductionOrder.objects.get_latest_num())
            obj.editor = request.user.email
            obj.status = 'P'
            if obj.issued_by == 'O':
                obj.issued_by_text = request.REQUEST.get('issued_by_text')
        else:
            if 'status' in form.changed_data:
                status_before = get_object_or_404(ProductionOrder, pk=obj.pk).status
                status_after = obj.status
                OrderStatusRecord.objects.create(order=obj, editor=request.user.email,
                    status_before=status_before, status_after=status_after,
                    time=timezone.now())
                if obj.status == 'C':
                    obj.confirmed_date = timezone.now().date()
                    Project.objects.get_or_create(order=obj, defaults={
                        'editor': request.user.email,
                        'division': obj.to, 'team': obj.assign_team, 'pjm': obj.assign_pjm,
                        'studio': obj.studio,
                        'working_title': obj.working_title, 'prj_id': 'PRJ-%s%02i%02i%02i' %\
                        (now.year, now.month, now.day, Project.objects.get_latest_num())})
            if obj.status == 'C':
                prj = obj.project
                prj.team = obj.assign_team
                prj.pjm = obj.assign_pjm
                prj.save()
        obj.save()


class ProcedureInline(admin.TabularInline):
    model = Procedure
    can_delete = False
    extra = 0
    form = ProcedureForm
    suit_classes = 'suit-tab suit-tab-procedure'
    readonly_fields = ('name',)
    fieldsets = ((None, {'fields': ('name', 'progress', 'staffing')}),)

    def get_formset(self, request, obj=None, **kwargs):
        if obj:
            self.max_num = obj.procedure_set.count()
        return admin.TabularInline.get_formset(self, request, obj=obj, **kwargs)


class ProjectAdmin(admin.ModelAdmin):
    list_per_page = 20
    list_display = ('prj_id', 'working_title', 'get_status', 'tier', 'get_plan_start', 'get_real_start',
        'get_plan_end', 'get_brief', 'get_pjm', 'studio', 'get_prd_status', 'get_art_status', 'get_content_status',
        'get_ui_ue_status', 'get_mkt_status', 'get_sound_status', 'get_code_status',
        'get_qa_status', 'get_tasks')
    list_filter = ('status', 'team', 'pjm', 'order__studio', 'order__studio_clouds', 'tier')
    search_fields = ('order__ref_num',)
    filter_horizontal = ('tasks',)
    form = ProjectAdminForm
    add_info_fields = (None, {'classes': ('suit-tab', 'suit-tab-info'),
        'fields': ('working_title', 'division', 'team', 'pjm', 'studio',
                   'status', 'tier', 'plan_start', 'plan_end', 'real_start',
                   'tasks')})
    info_fields = (None, {'classes': ('suit-tab', 'suit-tab-info'),
        'fields': ('prj_id', 'working_title', 'get_brief', 'get_division_and_team', 'get_pjm',
                   'get_studio', 'editor', 'created_time', 'status', 'tier', 'plan_start', 'plan_end',
                   'real_start', 'tasks')})
    procedure_fields = ('Procedure', {'classes': ('suit-tab', 'suit-tab-info'),
        'fields': ('proce',)})
    stats_fields = (None, {'classes': ('suit-tab', 'suit-tab-stats'),
        'fields': ('get_first_submission_date', 'get_latest_submission_date',
                   'get_latest_release_date', 'get_turnaround_time', 'get_lead_time',
                   'get_lag_time', 'get_full_circle_time')})

    class Media:
        js = ('base/js/custom_project.js',)

    @field('Status', admin_order_field='status')
    def get_status(self, obj):
        if obj.status == 'B':
            status = 'WTS'
        elif obj.status == 'A':
            status = 'WIP'
        elif obj.status == 'X':
            status = 'DONE'
        elif obj.status == 'Z':
            status = 'CXL'
        else:
            status = 'HOLD'
        return status

    @field('Studio')
    def get_studio(self, obj):
        return obj.studio

    @field('Actual Finish Date 1 - First Submission')
    def get_first_submission_date(self, obj):
        tasks = obj.tasks.filter(status__in=['S', 'L']).order_by('date_submitted')[:1]
        return tasks[0].date_submitted or '' if tasks else ''

    @field('Actual Finish Date 2 - Latest Submission')
    def get_latest_submission_date(self, obj):
        tasks = obj.tasks.filter(status__in=['S', 'L']).order_by('-date_submitted')[:1]
        return tasks[0].date_submitted or '' if tasks else ''

    @field('Actual Finish Date 3 - All Live')
    def get_latest_release_date(self, obj):
        tasks = obj.tasks.filter(status__in=['S', 'L'])
        dates = []
        for t in tasks:
            date = t.get_release_date()
            if date:
                dates.append(date)
        dates.sort(reverse=True)
        return dates[0] if dates else ''

    @field('Project Turnaround time')
    def get_turnaround_time(self, obj, display=True):
        try:
            date1 = self.get_first_submission_date(obj)
            delta = date1 - obj.real_start
            if obj.real_start and date1:
                if display:
                    return '%s Day(s)' % delta.days
                return delta.days
            return ''
        except Exception, e:
            print e
            return ''

    @field('Lead Time')
    def get_lead_time(self, obj, display=True):
        try:
            delta = obj.real_start - obj.order.date_issued
            if display:
                return '%s Day(s)' % delta.days
            return delta.days
        except Exception, e:
            print e
            return ''

    @field('Lag Time')
    def get_lag_time(self, obj, display=True):
        try:
            delta = (self.get_latest_release_date(obj) - self.get_first_submission_date(obj))
            if display:
                return '%s Day(s)' % delta.days
            return delta.days
        except TypeError:
            return ''

    @field('Full Circle Time')
    def get_full_circle_time(self, obj):
        try:
            days = int(self.get_turnaround_time(obj, False)) + int(self.get_lead_time(obj, False)) + int(self.get_lag_time(obj, False))
            return '%s Day(s)' % days
        except Exception, e:
            print e
            return ''

    @field('Production Output', allow_tags=True)
    def get_tasks(self, obj):
        return '<br />'.join(["<a href='/admin/app_info/app/%s/#version' target='_blank'>%s (V%s)</a> - %s" %\
            (t.app_id, t.app.prj_code, t.code, t.get_status_display()) for t in obj.tasks.all()])

    @field('Planned Start At', admin_order_field='plan_start')
    def get_plan_start(self, obj):
        return obj.plan_start or ''

    @field('Planned Finish At', admin_order_field='plan_end')
    def get_plan_end(self, obj):
        return obj.plan_end or ''

    @field('Actual Start At', admin_order_field='real_start')
    def get_real_start(self, obj):
        return obj.real_start or ''

    def get_procedure(self, obj, name, html=False):
        proce = obj.procedure_set.filter(name=name)[:1]
        if not html:
            return proce[0] if proce else None
        return "<div class=%s style='text-align: center;'>%s</div>" %\
            (proce[0].progress if proce else 'NO_NEED', '<br />'.join(proce[0].get_staffing()) if proce else '/')

    @field('PRD', allow_tags=True)
    def get_prd_status(self, obj):
        return self.get_procedure(obj, 'PRD', True)

    @field('Art', allow_tags=True)
    def get_art_status(self, obj):
        return self.get_procedure(obj, 'Art', True)

    @field('Content', allow_tags=True)
    def get_content_status(self, obj):
        return self.get_procedure(obj, 'Content', True)

    @field('UI/UE', allow_tags=True)
    def get_ui_ue_status(self, obj):
        return self.get_procedure(obj, 'UI/UE', True)

    @field('Sound', allow_tags=True)
    def get_sound_status(self, obj):
        return self.get_procedure(obj, 'Sound', True)

    @field('Code', allow_tags=True)
    def get_code_status(self, obj):
        return self.get_procedure(obj, 'Code', True)

    @field('Mkt. Assets', allow_tags=True)
    def get_mkt_status(self, obj):
        return self.get_procedure(obj, 'Marketing Assets', True)

    @field('Dev QA', allow_tags=True)
    def get_qa_status(self, obj):
        return self.get_procedure(obj, 'Dev QA', True)

    @field('Production Brief ID', admin_order_field='order__ref_num', allow_tags=True)
    def get_brief(self, obj):
        if not obj.order:
            return 'N/A'
        return "<a target='_blank' href='/admin/prd_order/productionorder/%s/'>%s</a>" %\
            (obj.order_id, obj.order.ref_num)

    @field('Division & Production Team')
    def get_division_and_team(self, obj):
        return '%s - %s' % (obj.division, obj.team)

    @field('Responsible PJM', admin_order_field='pjm')
    def get_pjm(self, obj):
        return obj.pjm

    def save_formset(self, request, form, formset, change):
        formset.save()
        obj = form.instance
        if not obj.status == 'Z':
            if formset.model == Procedure:
                if formset.save(commit=False):  # procedure status changed
                    progresses = obj.procedure_set.values_list('progress', flat=True)
                    progresses = list(set(progresses))
                    if progresses == ['WTS']:
                        obj.status = 'B'
                    else:
                        if progresses == ['DONE']:
                            obj.status = 'X'
                        else:
                            obj.status = 'A'
                    obj.save()

    def get_fieldsets(self, request, obj=None):
        base = (('info', 'Project Info'),)
        if not obj:
            self.suit_form_tabs = base
            return (self.add_info_fields,)
        fieldsets = (self.info_fields,)
        if obj and obj.tasks.count() > 0:
            base += (('stats', 'Statistics'),)
            fieldsets += (self.stats_fields,)

        if obj and not obj.get_proce():
            self.suit_form_tabs = base
            fieldsets += (self.procedure_fields,)
            return fieldsets
        else:
            base = list(base)
            base.insert(1, ('procedure', 'Procedure'))
            base = tuple(base)
            self.suit_form_tabs = base
            return fieldsets

    def get_inline_instances(self, request, obj=None):
        if obj and obj.get_proce():
            self.inlines = [ProcedureInline]
        else:
            self.inlines = []
        return admin.ModelAdmin.get_inline_instances(self, request, obj=obj)

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = admin.ModelAdmin.get_actions(self, request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    def get_readonly_fields(self, request, obj=None):
        base = ('prj_id', 'editor', 'created_time', 'order', 'get_brief',
            'get_division_and_team', 'get_pjm', 'get_studio')
        if obj:
            base += ('division', 'team', 'pjm', 'working_title', 'studio')
        if obj and obj.get_proce():
            base += ('proce',)
        if obj and obj.tasks.count() > 0:
            base += ('get_first_submission_date', 'get_latest_submission_date',
                     'get_latest_release_date', 'get_turnaround_time',
                     'get_lag_time', 'get_lead_time', 'get_full_circle_time')
        return base

    def response_change(self, request, obj):
        code_proce = self.get_procedure(obj, 'Code')
        prd_proce = self.get_procedure(obj, 'PRD')
        obj.tasks.all().update(ref_id=obj.order.ref_num if obj.order else "",
            programmer=code_proce.staffing or "" if code_proce else "",
            product_owner=prd_proce.staffing or "" if prd_proce else "")
        return admin.ModelAdmin.response_change(self, request, obj)

    def save_model(self, request, obj, form, change):
        if not change:
            now = timezone.now()
            obj.prj_id = 'PRJ-%s%02i%02i%02i' % (now.year, now.month, now.day,
                Project.objects.get_latest_num())
            obj.editor = request.user.email
        for p in form.cleaned_data.get('proce'):
            Procedure.objects.get_or_create(project=obj, name=p)
        obj.save()


admin.site.register(ProductionOrder, ProductionOrderAdmin)
admin.site.register(Project, ProjectAdmin)
